<?php

declare(strict_types=1);
/**
 * @author liguoxin
 * @email guoxinlee129@gmail.com
 */
namespace App\Exception;

use Hyperf\Contract\StdoutLoggerInterface;
use Hyperf\Di\Annotation\Inject;
use Hyperf\ExceptionHandler\ExceptionHandler;
use Hyperf\ExceptionHandler\Formatter\FormatterInterface;
use Hyperf\HttpMessage\Exception\HttpException;
use Hyperf\HttpMessage\Stream\SwooleStream;
use Hyperf\Server\Exception\ServerException;
use Hyperf\Validation\ValidationException;
use Psr\Http\Message\ResponseInterface;
use Throwable;

class Handler extends ExceptionHandler
{
    protected StdoutLoggerInterface $logger;

    /**
     * @Inject
     */
    protected FormatterInterface $formatter;

    public function __construct(StdoutLoggerInterface $logger)
    {
        $this->logger = $logger;
    }

    public function handle(Throwable $throwable, ResponseInterface $response): ResponseInterface
    {
        // $this->logger->debug($this->formatter->format($throwable));
        // $this->logger->error(sprintf('%s[%s] in %s', $throwable->getMessage(), $throwable->getLine(), $throwable->getFile()));
        // $this->logger->error($throwable->getTraceAsString());
        // var_dump($throwable->getHttpCode());
        $result['data'] = [];
        switch (true) {
            case $throwable instanceof ValidationException:
                $result['msg'] = $throwable->validator->errors()->first();
                $result['code'] = $throwable->getCode() === 0 ? -1 : $throwable->getCode();
                $httpCode = $throwable->status;
                break;
            # hyperf validate exception
            case $throwable instanceof HttpException:
                # hyperf http-message exception
                $array = explode('\\', get_class($throwable));
                $result['msg'] = __('messages.' . array_pop($array));
                $result['code'] = $throwable->getCode() === 0 ? -1 : $throwable->getCode();
                $httpCode = $throwable->statusCode;
                break;
            case $throwable instanceof ServerException:
                # hyperf server exception
                if (config('app_env') === 'dev') {
                    $array = explode('\\', get_class($throwable));
                    $result['msg'] = __('messages.' . array_pop($array));
                } else {
                    $result['msg'] = __('messages.ServerErrorHttpException');
                }
                $result['code'] = $throwable->getCode() === 0 ? -1 : $throwable->getCode();
                $httpCode = 500;
                break;
            case $throwable instanceof RuntimeException:
                # My System Exception
                $result['code'] = $throwable->getCode();
                $result['msg'] = $throwable->getMessage();
                $httpCode = $throwable->getHttpCode();
                if (isset($throwable->data)) {
                    $result['data'] = $throwable->data;
                }
                break;
            case $throwable instanceof \RuntimeException:
                # RuntimeException
                $result['code'] = $throwable->getCode();
                $result['msg'] = $throwable->getMessage();
                $httpCode = 400;
                break;
            case $throwable instanceof \LogicException:
            default:
                $result['msg'] = config('app_env') === 'dev' ? $throwable->getMessage() : __('messages.ServerErrorHttpException');
                $result['code'] = -1;
                $httpCode = 500;
        }

        if (is_array($result['data']) && $result['data']) {
            sort($result['data']);
        }
        if (! $result = json_encode($result, JSON_UNESCAPED_UNICODE)) {
            $result = '';
        }

        return $response
            ->withHeader('Content-Type', 'application/json;charset=utf-8')
            ->withStatus($httpCode)
            ->withBody(new SwooleStream($result));
    }

    public function isValid(Throwable $throwable): bool
    {
        return true;
    }
}
